

/*
函数映射到logical的Expr
*/

use crate::logical_plan::expr::LogicalPlanExpr;
use std::sync::Arc;
use crate::data_frame::{ElementValue, ConfValue, RealValue};
use crate::conf_parse::{Expression, parse, Ast};
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use crate::{and,lit,rep,dot,or,sub_rule};
use crate::conf_init::{MapResult, ResultErr};

#[derive(Debug)]
pub enum FuncArg{
    OtherExpr(String),  //<abc>
    Column(Vec<String>), //[a,b,c]
    Literal(String),     //abc
}

impl FuncArg{
    pub fn to_logical_plan(&self,pre_define: &HashMap<String,LogicalPlanExpr>)->MapResult<LogicalPlanExpr>{
        match self{
            FuncArg::OtherExpr(t) => {
                if let Some(other_expr) = pre_define.get(t){
                    return MapResult::Ok(other_expr.clone());
                }else{
                    return MapResult::Err(ResultErr::new(format!("OtherExpr not exist, {}", t)));
                }
            },
            FuncArg::Column(t) => {
                return MapResult::Ok(LogicalPlanExpr::Column(ElementValue{element:t.clone()}));
            },
            FuncArg::Literal(t) => {
                return MapResult::Ok(LogicalPlanExpr::LiteralConf(ConfValue::new(t.to_string())));
            },
        }
    }
}


static FUNC_RULE: OnceCell<Expression> = OnceCell::new();

pub fn logical_plan_func_rule_ref()->&'static Expression{
    let fr = FUNC_RULE.get_or_init(||{
        let func_arg_other_expr = and!(lit!("<"),rep!(dot!(),1,,lit!(">")),lit!(">"));
        let func_arg_column = and!(lit!("["),rep!(dot!(),1,,lit!("]")),lit!("]"));
        let func_arg_normal = rep!(dot!(),1,,or!(lit!(","),lit!(")")));
        let func_arg_enum = or!(sub_rule!("expr", func_arg_other_expr),
                        sub_rule!("column", func_arg_column),
                        sub_rule!("literal", func_arg_normal));
        let func_arg = and!(rep!(and!(sub_rule!("arg_enum",func_arg_enum),lit!(",")),,,),sub_rule!("arg_enum",func_arg_enum));
        let func_name = rep!(dot!(), 1, ,lit!("("));
        let func = and!(sub_rule!("func_name",func_name),lit!("("),sub_rule!("func_arg",func_arg),lit!(")"));

        func
    });

    return fr;
}

pub fn func_name_collect(func_name: &Ast) -> MapResult<String>{
    if let Ast::Rule((_, ref func_name_value)) = func_name{
        let mut tmp_name_value = String::new();

        for t in func_name_value.iter(){
            if let Ast::Value(t) = t{
                tmp_name_value.push_str(t.as_str());
            }else{
                let err_desc = format!("func_name_value not all Node::Value");
                return MapResult::Err(ResultErr::new(err_desc));
            }
        }

        if !tmp_name_value.is_empty(){
            return MapResult::Ok(tmp_name_value);
        }else{
            let err_desc = format!("func_name_value cannot be empty");
            return MapResult::Err(ResultErr::new(err_desc));
        }
    }else{
        let err_desc = format!("func_name_value must be rule");
        return MapResult::Err(ResultErr::new(err_desc));
    }
}

pub fn func_arg_collect(func_arg: &Ast) ->MapResult<Vec<FuncArg>>{
    if let Ast::Rule((_,ref func_arg)) = func_arg{
        let mut tmp = Vec::new();

        for t in func_arg.iter(){
            match t{
                Ast::Value(_) => {continue;},
                Ast::Rule((_,func_arg)) => {
                    //func_arg_enum
                    tmp.push(func_arg_collect_enum(func_arg)?);
                },
            }
        }

        //允许空参数函数
        return MapResult::Ok(tmp);
    }else{
        let err_desc = format!("func_arg [{:?}] must be rule", func_arg);
        return MapResult::Err(ResultErr::new(err_desc));
    }
}

pub fn func_arg_collect_enum(func_arg: &Vec<Ast>) ->MapResult<FuncArg>{
    if func_arg.len() == 1{
        if let Ast::Rule((func_arg_name, func_arg_value)) = &func_arg[0]{
            if func_arg_name == "expr"{
                let mut tmp = String::new();

                for t in func_arg_value.iter(){
                    if let Ast::Value(t) = t{
                        tmp.push_str(t.as_str());
                    }else{
                        let err_desc = format!("expr value not all Node::Value [{:?}]", func_arg_value);
                        return MapResult::Err(ResultErr::new(err_desc));
                    }
                }

                if let Some(tmp) = tmp.strip_prefix("<"){
                    if let Some(tmp) = tmp.strip_suffix(">"){
                        return MapResult::Ok(FuncArg::OtherExpr(tmp.to_string()));
                    }else{
                        let err_desc = format!("func arg expr not suffix >");
                        return MapResult::Err(ResultErr::new(err_desc));
                    }
                }else{
                    let err_desc = format!("func arg expr not prefix <");
                    return MapResult::Err(ResultErr::new(err_desc));
                }
            }else if func_arg_name == "column"{
                let mut tmp = Vec::new();
                let mut element = String::new();
                for t in func_arg_value.iter(){
                    if let Ast::Value(t) = t{
                        if t == "[" || t == "]" {
                            continue;
                        }
                        element.push_str(t.as_str());
                    }else{
                        let err_desc = format!("column value not all Node::Value [{:?}]", func_arg_value);
                        return MapResult::Err(ResultErr::new(err_desc));
                    }
                }
                let element: Vec<&str> = element.split(",").collect();
                for e in element.iter(){
                    tmp.push(e.to_string());
                }

                if !tmp.is_empty(){
                    return MapResult::Ok(FuncArg::Column(tmp));
                }else{
                    let err_desc = format!("column cannot be empty");
                    return MapResult::Err(ResultErr::new(err_desc));
                }
            }else if func_arg_name == "literal"{
                let mut tmp = String::new();
                for t in func_arg_value.iter(){
                    if let Ast::Value(t) = t{
                        tmp.push_str(t.as_str());
                    }else{
                        let err_desc = format!("column value not all Node::Value [{:?}]", func_arg_value);
                        return MapResult::Err(ResultErr::new(err_desc));
                    }
                }
                if !tmp.is_empty(){
                    return MapResult::Ok(FuncArg::Literal(tmp));
                }else{
                    let err_desc = format!("column cannot be empty");
                    return MapResult::Err(ResultErr::new(err_desc));
                }
            }else{
                let err_desc = format!("func_arg_name [{}] not support", func_arg_name);
                return MapResult::Err(ResultErr::new(err_desc));
            }
        }else{
            let err_desc = format!("func_arg ast [{:?}] must be rule", func_arg);
            return MapResult::Err(ResultErr::new(err_desc));
        }
    }else {
        let err_desc = format!("func_arg ast [{:?}] len must eq 1", func_arg);
        return MapResult::Err(ResultErr::new(err_desc));
    }
}